// const backSkinConfig = {
//   backgroundStyle: '#000000', // 画布背景样式
//   lineStyle: '#00ffff', // 连接线样式
//   pelStyle: '#ffff00', // 图元线条样式

//   titleStyle: '#ffff00', // 图元标题样式
//   titleFont: null, // 图元标题字体样式
//   dataTagStyle: '#00ff00', // 图元参数样式
//   dataTagFont: null, // 图元参数字体样式
//   dataStyle: '#ffffff', // 图元数据样式
//   dataFont: null // 图元数据字体样式
// }
const defaultSkinConfig = {
  backgroundStyle: null, // 画布背景样式
  lineStyle: '#ff9900', // 连接线样式
  pelStyle: '#0000ff', // 图元线条样式

  titleStyle: '#0000ff', // 图元标题样式
  titleFont: null, // 图元标题字体样式
  dataTagStyle: '#008000', // 图元参数样式
  dataTagFont: null, // 图元参数字体样式
  dataStyle: '#000000', // 图元数据样式
  dataFont: null // 图元数据字体样式
}
const defaultConfig = {
  showGrid: 'false',
  showTags: [], // 允许显示的参数
  defaultStateStyle: null, // 默认图元填充样式
  normalStateStyle: '#ff0000', // 正常状态图元填充样式
  abnormalStateStyle: '#00ff00', // 非正常状态图元填充样式
  canvasId: 'canvas',
  context: '2d',
  canvasWidth: 1200,
  canvasHeight: 1000,
  zoomX: 1,
  zoomY: 1,
  startX: 60,
  startY: 60,
  alignX: 'start',
  alignY: 'top',
  gridStyle: 'gray',
  gridSpace: 20,
  gridLineWidth: 1,
  lineWidth: 2, // 连接线宽度
  pelLineWidth: 2, // 图元线条宽度
  pelSpaceX: 60, // 图元的横向间隔,建议horizontal_space:pel_length
  pelSpaceY: 100, // 图元的纵向间隔,建议vertical_space:pel_length
  pelWidth: 10, // 图元的标准宽度,横向图元则为标准高度,建议spec_height/pel_width:8
  pelLength: 80, // 图元的标准长度,横向图元则为标准宽度,建议spec_height/pel_width:8
  textSpace: 10, // 图元中心与文字左侧的间隔
  textWidth: 100, // 文本的最大宽度
  textHeight: 15, // 文本的最大高度
  boxLineWidth: 2, //
  boxStyle: 'gray', //
  boxUnitWidth: 200, //
  boxUnitHeight: 100, //
  // 默认皮肤样式
  ...defaultSkinConfig
}

// 存放渲染一次系统图的详细数据
// width,Height,图元的宽和高
// (x,y),图元起点位置
// end(x,y),图元终点位置
// connect_pre(x,y),连接前一图元的位置,默认为起点(x,y)
// connect_next(x,y),,连接后一图元的位置,默认为终点end(x,y)
// title(x,y),图元标题起点位置
// data(x,y),图元数据起点位置
// data(width,height),图元数据区域宽度与高度
export default class MonitorChart {
  canvas = null;
  context = null;
  config = {};
  chartJson = {};
  idMapUid = {};
  // 构造函数,new MonitorCHart()时默认执行
  constructor(canvasId, configJson = {}) {
    let originPoint = { x: 0, y: 0 }
    this.config = { ...defaultConfig, ...configJson }
    this.config.canvasId = canvasId || this.config.canvasId
    this.canvas = document.getElementById(this.config.canvasId)
    this.context = this.canvas.getContext(this.config.context)
    this.canvas.draggable = true
    this.init()
    const _this = this
    this.canvas.addEventListener('dragend', function(event) {
    })
    this.canvas.addEventListener('dragover', function(event) {
      event.preventDefault()
      event.stopPropagation()
    })
    this.canvas.addEventListener('dragenter', function(event) {
      event.preventDefault()
      event.stopPropagation()
    })
    this.canvas.addEventListener('drag', function(event) {
      const newPosition = { x: event.clientX, y: event.clientY }
      _this.config.startX += (newPosition.x - originPoint.x)
      _this.config.startY += (newPosition.y - originPoint.y)
      _this.draw()
      originPoint = newPosition
    })
    this.canvas.addEventListener('mousewheel', function(event) {
      event.preventDefault()
      event.stopPropagation()
      _this.zoom(1 + event.deltaY / 1000, 1 + event.deltaY / 1000)
    })
    this.canvas.addEventListener('mousedown', function(event) {
      originPoint.x = event.clientX
      originPoint.y = event.clientY
    })
  }

  // 初始化环境
  init() {
    this.canvas.width = this.config.canvasWidth
    this.canvas.height = this.config.canvasHeight
    this.context.textAlign = this.config.alignX
    this.context.textBaseline = this.config.alignY
    this.context.clearRect(0, 0, this.config.canvasWidth, this.config.canvasHeight)
    if (this.config.backgroundStyle) {
      this.context.fillStyle = this.config.backgroundStyle
      this.context.fillRect(0, 0, this.config.canvasWidth, this.config.canvasHeight)
    }
    this.context.scale(this.config.zoomX, this.config.zoomY)
    if (this.config.showGrid) {
      switch (this.config.showGrid.trim().toUpperCase()) {
        case 'TRUE' :
          this.context.lineWidth = this.config.gridLineWidth
          this.context.strokeStyle = this.config.gridStyle
          this.drawGrid(0, 0, this.config.canvasWidth / this.config.zoomX, this.config.canvasHeight / this.config.zoomY, this.config.gridSpace)
          break
        default :
          break
      }
    }
    this.context.translate(this.config.startX, this.config.startY)
  }

  // 获取点击的图元信息
  getPel(event) {
    const eventX = (event.clientX - this.canvas.getBoundingClientRect().left) / this.config.zoomX - this.config.startX
    const eventY = (event.clientY - this.canvas.getBoundingClientRect().top) / this.config.zoomY - this.config.startY
    for (const key in this.chartJson) {
      if (this.chartJson[key].focus_x) {
        if (eventX > this.chartJson[key].focus_x && eventX < this.chartJson[key].focus_end_x && eventY > this.chartJson[key].focus_y && eventY < this.chartJson[key].focus_end_y) {
          return this.chartJson[key]
        }
      }
    }
    return null
  }

  // 缩放功能
  zoom(x, y) {
    if (x > 0 && y > 0) {
      this.config.zoomX *= x
      this.config.zoomY *= y
      this.draw()
    }
  }

  // 根据图元数据渲染图元
  draw(pelJson = this.chartJson) {
    this.init()
    this.drawChart(pelJson)
  }

  // 加载数据并绘图
  load(layoutJson) {
    // try {
    if (layoutJson && typeof (layoutJson) === 'object') {
      this.chartJson = this.getChartJson(layoutJson)
      this.draw()
    } else {
      return false
    }
    // } catch (e) {
    //   return false;
    // }
    return true
  }

  // 根据图元数据渲染图元
  drawChart(chartJson = this.chartJson, ctx = this.context, config = this.config) {
    for (const key in chartJson) {
      // 渲染图元
      ctx.lineWidth = config.boxLineWidth
      ctx.strokeStyle = config.boxStyle
      let style = null
      if (chartJson[key].status === null) {
        style = config.defaultStateStyle
      } else if (chartJson[key].status === '1') {
        style = config.normalStateStyle
      } else {
        style = config.abnormalStateStyle
      }
      this.drawPel(chartJson[key], style)
      // 填充标题
      ctx.fillStyle = config.titleStyle
      ctx.font = config.titleFont
      // TODO,must delete '+ chartJson[key].type' before publish
      if (chartJson[key].title_y === 0) {
        ctx.textAlign = 'center'
        ctx.fillText(chartJson[key].name, chartJson[key].title_x + chartJson[key].width / 2, config.textHeight / 2)
      } else {
        ctx.textAlign = 'left'
        ctx.fillText(chartJson[key].name, chartJson[key].title_x, chartJson[key].title_y)
      }
      // 填充开关图像
      if (!chartJson[key].children) {
        this.fillBoxImg(chartJson[key].focus_x, chartJson[key].focus_y, chartJson[key].status, chartJson[key].focus_end_x - chartJson[key].focus_x, chartJson[key].focus_end_y - chartJson[key].focus_y)
      }
      // 填充数据
      if (chartJson[key].data) {
        this.fillData(chartJson[key].data_x, chartJson[key].data_y, chartJson[key].data, config.textHeight, chartJson[key].data_width, chartJson[key].data_height)
      }
    }
  }

  // 填充数据
  // 起点坐标(x,y),数据内容data
  // 宽度width默认150;高度length,默认width/3
  fillData(x = 0, y = 0, data = null, textHeight = this.config.textHeight, width = textHeight * 9, height = textHeight * 3, ctx = this.context, config = this.config) {
    if (data) {
      let lengthLeft = 0
      for (const key in data) {
        lengthLeft = Math.max(lengthLeft, ctx.measureText(key + ': ').width)
      }
      const lengthRight = width / 3 - lengthLeft
      let top = y
      let left = x + lengthLeft
      for (const key in data) {
        ctx.fillStyle = config.tagStyle
        ctx.font = config.tagFont
        ctx.textAlign = 'right'
        ctx.fillText(key + ': ', left, top, lengthLeft)
        ctx.fillStyle = config.dataStyle
        ctx.font = config.dataFont
        ctx.textAlign = 'left'
        ctx.fillText(data[key], left, top, lengthRight)
        top += textHeight
        if (height - textHeight < top - y) {
          top = y
          left += (lengthLeft + lengthRight)
          if (x + width <= left) {
            left = x + lengthLeft
          }
        }
      }
    }
  }

  // 渲染状态
  // 起点坐标(x,y),宽度width,默认10;高度height,默认3倍width
  fillPel(style = null, x = 0, y = 0, width = 10, height = width * 3, ctx = this.context) {
    ctx.fillStyle = style
    // TODO
  }
  // 柜子-开关
  fillBoxImg(x = 0, y = 0, status = null, width = 20, height = 20, style = '#fff', ctx = this.context) {
    // ctx.fillRect(x, y, width, height);
    x = x + 20
    // 状态设置
    var strokeRed = ctx.createLinearGradient(x, y + 18, x, y + 50)
    strokeRed.addColorStop(0, '#d3d3d3')
    strokeRed.addColorStop(1, '#eb2403')
    var fillRed = ctx.createLinearGradient(x, y + 18, x, y + 50)
    fillRed.addColorStop(0, '#e18576')
    fillRed.addColorStop(1, '#eb2403')

    var strokeGreen = ctx.createLinearGradient(x, y + 18, x, y + 50)
    strokeGreen.addColorStop(0, '#9bdba6')
    strokeGreen.addColorStop(1, '#48d35f')
    var fillGreen = ctx.createLinearGradient(x, y + 18, x, y + 50)
    fillGreen.addColorStop(0, '#8cec9c')
    fillGreen.addColorStop(1, '#3ec955')

    var strokeGray = ctx.createLinearGradient(x, y + 18, x, y + 50)
    strokeGray.addColorStop(0, '#aaa9a8')
    strokeGray.addColorStop(1, '#7b7b7b')
    var fillGray = ctx.createLinearGradient(x, y + 18, x, y + 50)
    fillGray.addColorStop(0, '#b0b0b0')
    fillGray.addColorStop(1, '#838383')

    // 状态设置
    let boxstrokestyle = strokeGray
    let boxfillstyle = fillGray
    let rang = 45
    if (status === null) {
      boxstrokestyle = strokeGray
      boxfillstyle = fillGray
      rang = 45
    } else if (status === '1') {
      boxstrokestyle = strokeRed
      boxfillstyle = fillRed
      rang = 0
    } else {
      boxstrokestyle = strokeGreen
      boxfillstyle = fillGreen
      rang = 90
    }

    ctx.save()
    ctx.translate(x + 20, y + 30)
    ctx.rotate(-rang * Math.PI / 180)
    ctx.translate(-(x + 20), -(y + 30))

    // 开关圆形底，半径20
    ctx.beginPath()
    var boxstyle1 = ctx.createLinearGradient(x, y, x, y + 40)
    boxstyle1.addColorStop(0, '#969696')
    boxstyle1.addColorStop(1, '#2d2d2d')
    ctx.fillStyle = boxstyle1
    ctx.arc(x + 20, y + 20, 20, 0, 2 * Math.PI)
    ctx.fill()

    ctx.beginPath()
    ctx.strokeStyle = '#474747'
    ctx.lineWidth = 1
    ctx.arc(x + 20, y + 20, 15, 0, 2 * Math.PI)
    ctx.stroke()

    ctx.beginPath()
    ctx.strokeStyle = '#212121'
    ctx.lineWidth = 1
    var boxstyle2 = ctx.createLinearGradient(x, y + 6, x, y + 28)
    boxstyle2.addColorStop(0, '#6d6d6d')
    boxstyle2.addColorStop(1, '#888888')
    ctx.fillStyle = boxstyle2
    ctx.arc(x + 20, y + 20, 14, 0, 2 * Math.PI)
    ctx.stroke()
    ctx.fill()

    ctx.beginPath()
    var boxstyle3 = ctx.createLinearGradient(x, y + 7, x, y + 26)
    boxstyle3.addColorStop(0, '#262626')
    boxstyle3.addColorStop(1, '#888888')
    ctx.fillStyle = boxstyle3
    ctx.arc(x + 20, y + 20, 13, 0, 2 * Math.PI)
    ctx.fill()

    // 开关把手
    ctx.beginPath()
    var boxstyle4 = ctx.createLinearGradient(x, y + 10, x, y + 60)
    boxstyle4.addColorStop(0, '#363636')
    boxstyle4.addColorStop(0.3, '#333333')
    boxstyle4.addColorStop(0.5, '#717171')
    boxstyle4.addColorStop(1, '#474747')
    ctx.strokeStyle = boxstyle4
    ctx.lineWidth = 2
    var boxstyle5 = ctx.createLinearGradient(x, y + 10, x, y + 60)
    boxstyle5.addColorStop(0, '#292929')
    boxstyle5.addColorStop(0.3, '#505050')
    boxstyle5.addColorStop(0.5, '#393939')
    boxstyle5.addColorStop(1, '#000000')
    ctx.fillStyle = boxstyle5
    ctx.moveTo(x + 13, y + 20)
    ctx.arcTo(x + 14, y + 12, x + 20, y + 12, 7)
    ctx.arcTo(x + 26, y + 12, x + 26, y + 16, 7)
    ctx.arcTo(x + 27, y + 60, x + 22, y + 60, 6)
    ctx.arcTo(x + 13, y + 60, x + 13, y + 54, 6)
    ctx.closePath()
    ctx.stroke()
    ctx.fill()

    // 开关状态
    ctx.beginPath()
    ctx.lineWidth = 1
    ctx.strokeStyle = boxstrokestyle
    ctx.fillStyle = boxfillstyle
    ctx.moveTo(x + 16, y + 25)
    ctx.arcTo(x + 16, y + 18, x + 20, y + 18, 4)
    ctx.arcTo(x + 24, y + 18, x + 24, y + 20, 4)
    ctx.arcTo(x + 24, y + 47, x + 20, y + 47, 4)
    ctx.arcTo(x + 16, y + 47, x + 16, y + 45, 4)
    ctx.closePath()
    ctx.stroke()
    ctx.fill()

    // 恢复旋转前画布设置
    ctx.restore()

    // 信号灯
    ctx.beginPath()
    ctx.lineWidth = 2
    ctx.strokeStyle = '#474747'
    ctx.fillStyle = '#969696'
    ctx.arc(x + 63, y + 30, 4, 0, 2 * Math.PI)
    ctx.stroke()
    ctx.fill()
    ctx.beginPath()
    ctx.fillStyle = boxfillstyle
    ctx.arc(x + 63, y + 30, 3, 0, 2 * Math.PI)
    ctx.fill()
    // 拉环
    var boxstyle6 = ctx.createLinearGradient(x, y + height - 10, x, y + height - 5)
    boxstyle6.addColorStop(0, '#747f7b')
    boxstyle6.addColorStop(0.7, '#27322e')
    boxstyle6.addColorStop(1, '#5d736e')
    ctx.fillStyle = boxstyle6
    this.drawRoundRect(ctx, x - 10, y + height - 10, 30, 5, 2)
    this.drawRoundRect(ctx, x + width * 2 - 60, y + height - 10, 30, 5, 2)
  }
  // 画开关柜拉环方法
  drawRoundRect(ctx, x, y, width, height, radius) {
    ctx.beginPath()
    ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2)
    ctx.lineTo(width - radius + x, y)
    ctx.arc(width - radius + x, radius + y, radius, Math.PI * 3 / 2, Math.PI * 2)
    ctx.lineTo(width + x, height + y - radius)
    ctx.arc(width - radius + x, height - radius + y, radius, 0, Math.PI * 1 / 2)
    ctx.lineTo(radius + x, height + y)
    ctx.arc(radius + x, height - radius + y, radius, Math.PI * 1 / 2, Math.PI)
    ctx.closePath()
    ctx.fill()
  }

  // 柜子
  drawBox(x = 0, y = 0, width = 20, height = 20, style = null, ctx = this.context) {
    ctx.beginPath()
    ctx.fillStyle = style
    ctx.strokeRect(x, y, width, height)
    ctx.stroke()
  }

  // 画网格线
  drawGrid(x = 0, y = 0, width = 800, height = 600, space = 10, ctx = this.context) {
    ctx.beginPath()
    for (let dx = x; dx < x + width; dx += space) {
      ctx.moveTo(dx, y)
      ctx.lineTo(dx, y + height)
    }
    for (let dy = y; dy < y + height; dy += space) {
      ctx.moveTo(x, dy)
      ctx.lineTo(x + width, dy)
    }
    ctx.stroke()
  }

  // 更新数据,dataJson格式如下
  // {
  //  point_id:"",
  //  status:{
  //    flag:""
  //  },
  //  data:{
  //    tagId:"tagValue"
  //  }
  // }
  update(dataJson, chartJson = this.chartJson) {
    var pelId = null
    if (dataJson && dataJson.point) {
      pelId = dataJson.point
      if (chartJson[this.idMapUid[pelId]]) {
        if (dataJson.status && dataJson.status.sw != null) {
          chartJson[this.idMapUid[pelId]].status = dataJson.status.sw
        }
        if (dataJson.data) {
          chartJson[this.idMapUid[pelId]].data = Object.assign({}, chartJson[this.idMapUid[pelId]].data, this.flitrateData(dataJson.data))
        }
        this.draw(chartJson)
      }
    }
  }

  // 仅更新状态
  updateStatus(pelId, flag) {
    if (pelId != null && flag != null) {
      this.chartJson[pelId].status = flag
      var style = null
      if (flag == null) {
        style = this.config.defaultStateStyle
      } else if (flag) {
        style = this.config.normalStateStyle
      } else {
        style = this.config.abnormalStateStyle
      }
      this.drawPel(this.chartJson[pelId], style)
    }
  }

  // 仅更新数据,dataJson格式如下
  // {
  //  tagId:"tagValue"
  // }
  updateData(pelId, dataJson, ctx = this.context) {
    if (pelId != null && dataJson != null) {
      var datajson = this.flitrateData(dataJson)
      this.chartJson[pelId].data = datajson
      ctx.clearRect(this.chartJson[pelId].data_x, this.chartJson[pelId].data_y, this.chartJson[pelId].data_width, this.chartJson[pelId].data_height)
      if (this.config.backgroundStyle) {
        ctx.fillStyle = this.config.background_style
        ctx.fillRect(this.chartJson[pelId].data_x, this.chartJson[pelId].data_y, this.chartJson[pelId].data_width, this.chartJson[pelId].data_height)
      }
      this.fillData(this.chartJson[pelId].data_x, this.chartJson[pelId].data_y, datajson, this.config.textHeight, this.chartJson[pelId].data_width, this.chartJson[pelId].data_height)
    }
  }

  // 根据show_tag显示数组过滤数据
  // TODO reduce 重构
  flitrateData(dataJson, config = this.config) {
    var datajson = {}
    if (config.showTags.length > 0) {
      for (var i = 0; i < config.showTags.length; ++i) {
        if (dataJson[config.showTags[i]] != null) {
          datajson[config.showTags[i]] = (Math.ceil(dataJson[config.showTags[i]] * 100)) / 100
        }
      }
    } else {
      datajson = dataJson
    }
    return datajson
  }

  // 根据图元类别画图元
  drawPel(pelJson, style) {
    this.drawBox(pelJson.x, pelJson.y, pelJson.width, pelJson.height, style)
  }

  // / 解析布局数据为图元数据
  getChartJson(layoutData, config = this.config) {
    const resultData = {}
    let positionX = 0
    let positionY = 0
    // 整体柜子图形,
    const box = {
      x: 0,
      y: 0,
      width: layoutData.children.length * config.boxUnitWidth,
      height: 0
    }
    for (const cabinet of layoutData.children || []) {
      this.idMapUid[cabinet.id] = cabinet.uid
      // 各馈线柜图形,
      let cabinetHeigh = 0
      positionY = config.textHeight * 2
      resultData[cabinet.uid] = {
        ...cabinet,
        x: positionX,
        y: 0,
        title_x: positionX,
        title_y: 0,
        width: config.boxUnitWidth,
        height: config.textHeight * 2
      }
      for (const point of cabinet.children) {
        this.idMapUid[point.id] = point.uid
        // 监测点图形,各种形状
        const pel = {}
        const pelWidth = point.infobject && point.infobject.column ? parseInt(point.infobject.column) : 1
        const pelHeight = point.infobject && point.infobject.row ? parseInt(point.infobject.row) : 1
        pel.x = positionX
        pel.y = positionY
        pel.width = config.boxUnitWidth * pelWidth
        pel.height = config.boxUnitHeight * pelHeight
        pel.title_x = pel.x + config.textSpace
        pel.title_y = pel.y + config.textSpace

        pel.focus_x = pel.x
        pel.focus_y = pel.title_y + config.textHeight
        pel.focus_end_x = pel.focus_x + pel.width / 2
        pel.focus_end_y = pel.y + pel.height

        pel.data_x = pel.x + pel.width / 2
        pel.data_y = pel.y + config.textHeight * 2
        pel.data_width = pel.width / 2 - config.textSpace * 2
        pel.data_height = pel.height
        resultData[point.uid] = { ...point, ...pel }
        positionX = pel.x
        positionY = pel.y + pel.height
        cabinetHeigh += pel.height
      }
      positionX += config.boxUnitWidth
      box.height = Math.max(box.height, cabinetHeigh)
    }
    for (const cabinet of layoutData.children || []) {
      resultData[cabinet.uid].height += box.height
    }
    box.height += config.textHeight * 2
    resultData[layoutData.uid] = { ...layoutData, ...box }
    return resultData
  }
}
